package thread.forjoinpool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * 演示ForkJoinPool线程池的使用 模拟数列求和
 *
 * @author liweimin
 * @date 2021/5/24 16:24
 * @since
 */
public class Test1 {
    public static final Long VALUE = 1000000L;

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CountTask task = new CountTask(0L, VALUE);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        long currentTimeMillis = System.currentTimeMillis();
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);
        System.out.println("ForkJoinPoll计算结果：" + submit.get());
        System.out.println("ForkJoinPoll计算耗时：" + (System.currentTimeMillis() - currentTimeMillis) + "ms");

        long millis = System.currentTimeMillis();
        long sum = 0;
        for (long i = 0; i <= VALUE; i++) {
            sum += i;
        }
        System.out.println("普通累加计算结果：" + sum);
        System.out.println("普通累加计算耗时：" + (System.currentTimeMillis() - millis) + "ms");
    }

    /**
     * 计算数列求和需要返回值，继承RecursiveTask类
     */
    private static class CountTask extends RecursiveTask<Long> {
        //阈值 允许计算1000个数之内的和，超过这个阈值需要分解
        private static final int THRESHOLD = 10000;
        //每次都分解成100个任务
        private static final int TASK_NUM = 100;

        private long start;
        private long end;

        public CountTask(long start, long end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Long compute() {
            long sum = 0;//保存计算的结果
            //判断任务是否需要继续分解
            if (end - start <= THRESHOLD) {
                for (long i = start; i <= end; i++) {
                    sum += i;
                }
            } else {
                //约定每次分解成100任务
                long step = (end + start) / TASK_NUM;
                List<CountTask> list = new ArrayList<>();
                long position = start;
                for (int i = 0; i < TASK_NUM; i++) {
                    long lastPosition = position + step;
                    if (lastPosition > end) {
                        lastPosition = end;
                    }
                    CountTask countTask = new CountTask(position, lastPosition);
                    list.add(countTask);
                    countTask.fork();
                    position = lastPosition + 1;
                }
                for (CountTask countTask : list) {
                    sum += countTask.join();
                }
            }
            return sum;
        }
    }
}
